package com.yhb.service;


import com.yhb.channel.ChannelDispatcher;
import com.yhb.conf.Configuration;
import com.yhb.dao.RapidCheatMapper;
import com.yhb.dao.ThirdPurchaseFlowMapper;
import com.yhb.dao.UserMapper;
import com.yhb.model.MQMessage;
import com.yhb.model.RapidCheat;
import com.yhb.model.ThirdPurchaseFlow;
import com.yhb.model.mq.*;
import com.yhb.utils.DateUtils;
import com.yhb.yinsheng.UnionPayService;
import lombok.extern.log4j.Log4j;
import lombok.var;
import me.edzh.spring.bootstrap.utils.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

@Service
@Log4j
public class ScheduledService {

    @Autowired
    private RedisTemplate<String, String> redis;


    @Value("${CLUSTER_MODE}")
    private String clusterMode;

    private boolean shouldTick = false;

    @Autowired
    private UserMapper userMapper;

    @Qualifier("msgListener")
    @Autowired
    private MQService mqService;

    @Autowired
    private RapidCheatMapper rapidCheatMapper;

    @Autowired
    private ChannelDispatcher channelDispatcher;

    @Autowired
    private UnionPayService unionPayService;

    @Autowired
    private ThirdPurchaseFlowMapper thirdPurchaseFlowMapper;

    @PostConstruct
    public void init() {
        if ("TIMER".equals(this.clusterMode)) {
            shouldTick = true;
        }
    }

    @Scheduled(fixedDelay = 60 * 1000)
    public void syncConfigs() {
        var json = redis.boundValueOps(Configuration.KEY_CONFIG).get();
        try {
            Configuration.setConfigMap(JSONUtil.parseJson(json, Map.class));
        } catch (Throwable ignored) {

        }
    }

    @Scheduled(cron = "0 0 1 * * ?")
    public void startSumUpTradeFlows() {
        if (!shouldTick) {
            return;
        }


        List<String> rootUsers = userMapper.getRootUsers();
        String monthString = DateUtils.getYesterdayMonthString();
        String dateString = DateUtils.getYesterdayDateString();
        for (String userId : rootUsers) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_CALC_FLOW_SUM_UP)
                    .content(SumUpParam.builder()
                            .dateString(dateString)
                            .monthString(monthString)
                            .userId(userId)
                            .build())
                    .build();

            mqService.sendMsg(mqMessage);
        }
    }

    @Scheduled(cron = "0 45 21 * * ?")
    public void clearUserReservedBalance() {
        //定时执行日终清分，入队列 clearUserReservedBalance
        if (!shouldTick) {
            return;
        }


        List<String> rootUsers = userMapper.allUserIds();
        for (String userId : rootUsers) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_CLEAR_USER_RESERVED_BALANCE)
                    .content(SumUpParam.builder()
                            .userId(userId)
                            .build())
                    .build();

            mqService.sendMsg(mqMessage);
        }
    }

    @Scheduled(cron = "0 0 0 1 * ?")
    public void checkInviteeCertificate() {
        if (!shouldTick) {
            return;
        }

        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, -1);

        List<String> rootUsers = userMapper.allUserIds();
        for (String userId : rootUsers) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_CHECK_INVITEE_CERTIFICATE)
                    .content(TimeRangeParam.builder()
                            .userId(userId)
                            .startTime(DateUtils.getFirstDayFirstSecondThisMonth(c))
                            .endTime(DateUtils.getLastDayLastSecondThisMonth(c))
                            .build())
                    .build();

            mqService.sendMsg(mqMessage);
        }
    }

    @Scheduled(cron = "0 0 1 * * ?")
    public void startSumUpActiveUsers() {
        if (!shouldTick) {
            return;
        }

        var c = DateUtils.getYesterday();
        var endTime = c.getTime();
        c.add(Calendar.DAY_OF_MONTH, -60);
        DateUtils.setFirstTimeOfDay(c);
        var startTime = c.getTime();

        List<String> rootUsers = userMapper.getRootUsers();
        for (String userId : rootUsers) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_CALC_ACTIVE_USER)
                    .content(TimeRangeParam.builder()
                            .userId(userId)
                            .startTime(startTime)
                            .endTime(endTime)
                            .build())
                    .build();

            mqService.sendMsg(mqMessage);
        }
    }

    @Scheduled(cron = "0 0 2 * * SUN,TUE-SAT")
    public void sumUpMonthlyFlows() {
        if (!shouldTick) {
            return;
        }

        String monthString = DateUtils.getCurrentMonthString();
        MQMessage mqMessage = MQMessage.builder()
                .type(MQMessage.T_CALC_MONTHLY_FLOW_SUM_UP)
                .content(SumUpParam.builder()
                        .monthString(monthString)
                        .build())
                .build();

        mqService.sendMsg(mqMessage);
    }

    @Scheduled(cron = "0 0 2 * * MON")
    public void startCalculateApproximatelySplittings() { // 每周一2点开始估算收益
        if (!shouldTick) {
            return;
        }

        String monthString = DateUtils.getCurrentMonthString();
        MQMessage mqMessage = MQMessage.builder()
                .type(MQMessage.T_START_CALC_SPLITTINGS)
                .content(SumUpParam.builder()
                        .monthString(monthString)
                        .build())
                .build();

        mqService.sendMsg(mqMessage);
    }

    @Scheduled(cron = "0 0 6 * * MON")
    public void sumUpApproximatelyIncome() { // 每周一6点开始统计估算收益
        if (!shouldTick) {
            return;
        }

        var userIds = userMapper.allUserIds();

        String dateString = DateUtils.getYesterdayDateString();
        for (var id : userIds) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_SUM_UP_APPROXIMATELY_INCOME)
                    .content(SumUpParam.builder()
                            .dateString(dateString)
                            .userId(id)
                            .build())
                    .build();

            mqService.sendMsg(mqMessage);
        }
    }

    @Scheduled(cron = "0 0 2 1 * ?")
    public void startCalculateSplittings() {
        if (!shouldTick) {
            return;
        }

        String monthString = DateUtils.getLastMonthString();

        MQMessage mqMessage = MQMessage.builder()
                .type(MQMessage.T_START_CALC_SPLITTINGS)
                .content(SumUpParam.builder()
                        .monthString(monthString)
                        .build())
                .build();

        mqService.sendMsg(mqMessage);
    }

    @Scheduled(cron = "0 0 1 1 * ?")
    public void calcMonthlyActivateBonus() {
        if (!shouldTick) {
            return;
        }

        String monthString = DateUtils.getLastMonthString();
        List<String> rootUsers = userMapper.getRootUsers();
        for (var u : rootUsers) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_CALC_MONTHLY_ACTIVATE_BONUS)
                    .content(SumUpParam.builder()
                            .monthString(monthString)
                            .userId(u)
                            .build())
                    .build();

            mqService.sendMsg(mqMessage);
        }

    }

    @Scheduled(cron = "0 0 1 2 * ?")
    public void outputIncomeReport() {
        if (!shouldTick) {
            return;
        }

        String monthString = DateUtils.getLastMonthString();

        MQMessage mqMessage = MQMessage.builder()
                .type(MQMessage.T_START_OUTPUT_INCOME_REPORT)
                .content(SumUpParam.builder()
                        .monthString(monthString)
                        .build())
                .build();

        mqService.sendMsg(mqMessage);
    }

    @Scheduled(cron = "0 0 3 2 * ?")
    public void outputIncomeSummaryReport() {
        if (!shouldTick) {
            return;
        }

        String monthString = DateUtils.getLastMonthString();

        MQMessage mqMessage = MQMessage.builder()
                .type(MQMessage.T_START_OUTPUT_INCOME_SUMMARY_REPORT)
                .content(SumUpParam.builder()
                        .monthString(monthString)
                        .build())
                .build();

        mqService.sendMsg(mqMessage);
    }

    @Scheduled(cron = "*/10 * * * * ?")
    public void channelTicker() {
        if (!shouldTick) {
            return;
        }

        channelDispatcher.triggerAllChannelTicks();
    }

    @Scheduled(cron = "*/10 * * * * ?")
    public void queryUnionPayStatus() {
        if (!shouldTick) {
            return;
        }


        var c = Calendar.getInstance();
        c.add(Calendar.SECOND, -20);
        c.set(Calendar.YEAR, 2000);
        var list = rapidCheatMapper.statusListAfter(RapidCheat.Type.UNION_PAY_CHANNEL, RapidCheat.Status.CREATED, c.getTime());
        list.addAll(rapidCheatMapper.statusListAfter(RapidCheat.Type.UNION_PAY_CHANNEL, RapidCheat.Status.CONSUMED, c.getTime()));
        for (var order : list) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_QUERY_UNION_PAY_ORDER)
                    .content(QueryUnionPayOrderParam.builder()
                            .orderId(order.getId())
                            .rapidCheatId(order.getId())
                            .build())
                    .build();

            mqService.sendMsg(mqMessage);
        }

        var dates = DateUtils.dateStringsBackOff(2);
        log.info("query activeRemit flow of:" + dates);
        dates.forEach(dateString -> {
            var flows = unionPayService.getPendingFlowsOfDateString(dateString);
            flows.forEach(flow -> {
                MQMessage mqMessage = MQMessage.builder()
                        .type(MQMessage.T_QUERY_UNION_PAY_ACTIVE_REMIT)
                        .content(QueryUnionFlowParam.builder()
                                .id(flow.getId())
                                .dateString(dateString)
                                .build())
                        .build();

                mqService.sendMsg(mqMessage);
            });
        });
    }

    @Scheduled(cron = "0 */5 * * * ?")
    public void checkVipValid() {
        if (!shouldTick) {
            return;
        }

        var userIds = userMapper.allUserIds();

        for (var userId : userIds) {
            MQMessage mqMessage = MQMessage.builder()
                    .type(MQMessage.T_CHECK_VIP_VALID)
                    .content(SumUpParam.builder().userId(userId).build())
                    .build();

            mqService.sendMsg(mqMessage);
        }


    }

    @Scheduled(cron = "*/10 * * * * ?")
    public void syncLeshuaMerchant() {
        if (!shouldTick) {
            return;
        }

        log.info("syncLeshuaMerchant");
        Calendar c = Calendar.getInstance();
        var endTime = c.getTime();
        c.add(Calendar.SECOND, -20);
        var startTime = c.getTime();

        MQMessage mqMessage = MQMessage.builder()
                .type(MQMessage.T_SYNC_LESHUA_MERCHANTS)
                .content(TimeRangeParam.builder()
                        .startTime(startTime)
                        .endTime(endTime)
                        .build())
                .build();

        mqService.sendMsg(mqMessage);
    }

    @Scheduled(cron = "0 */20 * * * ?")
    public void syncLeshuaFlow() {
        if (!shouldTick) {
            return;
        }

        // 每20分钟同步前25分钟订单, 消费侧有排重.
        Calendar c = Calendar.getInstance();
        var endTime = c.getTime();
        c.add(Calendar.MINUTE, -25);
        var startTime = c.getTime();

        MQMessage mqMessage = MQMessage.builder()
                .type(MQMessage.T_SYNC_LESHUA_ORDERS)
                .content(TimeRangeParam.builder()
                        .startTime(startTime)
                        .endTime(endTime)
                        .build())
                .build();

        mqService.sendMsg(mqMessage);
    }


    @Scheduled(cron = "0 */1 * * * ?")
    public void callbackThirdFlows() {
        if (!shouldTick) {
            return;
        }

        var todayDateString = DateUtils.getCurrentDateString();
        var yesterdayDateString = DateUtils.getYesterdayDateString();

        List<ThirdPurchaseFlow> flows = new ArrayList<>();

        try {
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(todayDateString, 0, DateUtils.nowAdd(-5 * 60)));
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(todayDateString, 1, DateUtils.nowAdd(-30 * 60)));
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(todayDateString, 2, DateUtils.nowAdd(-120 * 60)));
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(todayDateString, 3, DateUtils.nowAdd(-12 * 60 * 60)));

            flows.forEach(flow -> {
                mqService.sendMsg(
                        MQMessage.builder()
                                .type(MQMessage.T_CALLBACK_THIRD_FLOW)
                                .content(IdParam.builder()
                                        .id(flow.getId())
                                        .dateString(todayDateString)
                                        .build())
                                .build());
            });

        } catch (Throwable t) {
            log.error("get today flows err", t);
        }

        flows.clear();

        try {
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(yesterdayDateString, 0, DateUtils.nowAdd(-5 * 60)));
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(yesterdayDateString, 1, DateUtils.nowAdd(-30 * 60)));
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(yesterdayDateString, 2, DateUtils.nowAdd(-120 * 60)));
            flows.addAll(thirdPurchaseFlowMapper.notSucceededCountFlowsBefore(yesterdayDateString, 3, DateUtils.nowAdd(-12 * 60 * 60)));

            flows.forEach(flow -> {
                mqService.sendMsg(
                        MQMessage.builder()
                                .type(MQMessage.T_CALLBACK_THIRD_FLOW)
                                .content(IdParam.builder()
                                        .id(flow.getId())
                                        .dateString(yesterdayDateString)
                                        .build())
                                .build());
            });
        } catch (Throwable t) {
            log.error("get yesterday flows err", t);

        }
    }


//    @Scheduled(cron = "*/5 * * * * ?")
//    public void test() {
//        log.info("tick");
//    }
}
